///////////////////////////////////////////////////////////////////////////////////////////////////
//to calculate the total CPU usage, on windows XP SP1 and windows 7 platform.
///////////////////////////////////////////////////////////////////////////////////////////////////
#if defined WIN32

#include <windows.h>
#include <stdio.h>
#include <conio.h>

class CCPUUseRate
{
public:
    CCPUUseRate()
		:gettimes(0)
		, average_cpu_age(0)
	{
		Initialize();
	};
    virtual ~CCPUUseRate(){};
    
    //to initialize the local variant when the system was started
    int Initialize(void)
	{
		FILETIME ftIdle, ftKernel, ftUser;
		int flag = FALSE;
		if (flag = GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
		{
			m_fOldCPUIdleTime = FileTimeToDouble(ftIdle);
			m_fOldCPUKernelTime = FileTimeToDouble(ftKernel);
			m_fOldCPUUserTime = FileTimeToDouble(ftUser);
		}
		return flag;
	}

	int GetDoTimes()
	{
		return gettimes;
	}
	
	int  GetCPUAverage()
	{
		int average_cpu_aget = average_cpu_age / gettimes;
		average_cpu_age = 0;
		gettimes = 0;

		return average_cpu_aget;
	}

    //to calculate the instant total CPU usage, period is at least 1 seconds
    int GetCPUUseRate(void)
	{
		int nCPUUseRate = -1;
		FILETIME ftIdle, ftKernel, ftUser;
		if (GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
		{
			double fCPUIdleTime = FileTimeToDouble(ftIdle);
			double fCPUKernelTime = FileTimeToDouble(ftKernel);
			double fCPUUserTime = FileTimeToDouble(ftUser);
			nCPUUseRate= (int)(100.0 - (fCPUIdleTime - m_fOldCPUIdleTime)
				/ (fCPUKernelTime - m_fOldCPUKernelTime + fCPUUserTime - m_fOldCPUUserTime) *100.0);
		    
			m_fOldCPUIdleTime = fCPUIdleTime;
			m_fOldCPUKernelTime = fCPUKernelTime;
			m_fOldCPUUserTime = fCPUUserTime;
		}

		gettimes ++ ;
		average_cpu_age += nCPUUseRate;

		return nCPUUseRate;
	}
	
private:
    //to convert the system time into the double data type
	double FileTimeToDouble(FILETIME &filetime)
	{
		return (double)(filetime.dwHighDateTime * 4.294967296E9) + (double)filetime.dwLowDateTime;
	}
	
private:
	double m_fOldCPUIdleTime;
	double m_fOldCPUKernelTime;
	double m_fOldCPUUserTime;

	int  gettimes;

	int average_cpu_age;
};

///////////////////////////////////////////////////////////////////////////////////////////////////
//to calculate the total CPU usage, on linux and (or) android platform.
///////////////////////////////////////////////////////////////////////////////////////////////////
#elif defined ANDROID || defined(WEBRTC_LINUX)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

class CCPUUseRate
{
public:
    CCPUUseRate(){};
    virtual ~CCPUUseRate(){};
    
    //to initialize the local variant when the system was started
	int Initialize(void)
	{
	    int retCode = 0;
	    long long lbusy = 0, ltotal = 0;
		retCode = GetSystemTimes(&lbusy, &ltotal);
	    if (retCode)
	    {
	        m_prevBusyTime  = lbusy;
	        m_prevTotalTime = ltotal;
	    }
	    else
	    {
	        m_prevBusyTime  = 0;
	        m_prevTotalTime = 0;
	    }
	    return retCode;
	}
	
	//to calculate the instant total CPU usage, period is at least 1 seconds
	int GetCPUUseRate(void)
	{
        long long lbusy = 0, ltotal = 0;
        if ((0) == GetSystemTimes(&lbusy, &ltotal))
        {
            return (0);
        }
        
        long long delta_busy  = lbusy  - m_prevBusyTime;
        long long delta_total = ltotal - m_prevTotalTime;
        
        m_prevBusyTime  = lbusy;
        m_prevTotalTime = ltotal;
        
        int total_cpu_usage = 0;
        if (delta_total > 0)
        {
            total_cpu_usage = (int)((100 * delta_busy) / (delta_total));
        }
        return total_cpu_usage;
	}

private:
    //to update the system time counter, get total time and busy time
    int GetSystemTimes(long long *busyTime, long long *totalTime)
    {
        FILE* fptr = fopen("/proc/stat", "r");
        if (fptr == NULL)
        {
            return (0);
        }
        
        char line[200];
        if (fgets(line, 200, fptr) == NULL)
        {
            fclose(fptr);
            return (0);
        }
        
        char s_cpu[100], s_user[100], s_nice[100], s_system[100], s_idle[100];
        if (sscanf(line, "%s %s %s %s %s ", s_cpu, s_user, s_nice, s_system, s_idle) != 5)
        {
            fclose(fptr);
            return (0);
        }
        
        if (strncmp(s_cpu, "cpu", 3) != 0)
        {
            fclose(fptr);
            return (0);
        }
        
        //to calculate the busy time and total CPU time, then output
        long long luser   = atoll(s_user);
        long long lnice   = atoll(s_nice);
        long long lsystem = atoll(s_system);
        long long lidle   = atoll(s_idle);
        
        *busyTime  = luser + lnice + lsystem;
        *totalTime = luser + lnice + lsystem + lidle;
        
        fclose(fptr);
        return (1);
    }
    
private:
    long long m_prevBusyTime;
    long long m_prevTotalTime;
};

#elif defined WEBRTC_IOS
#include "talk/base/cpumonitor.h"

class CCPUUseRate
{
public:
	CCPUUseRate(){};
	virtual ~CCPUUseRate(){};

	//to initialize the local variant when the system was started
	int Initialize(void)
	{
		if(!sampler_.Init()){
			return 0;
		}
		return 1;
	}

	//to calculate the instant total CPU usage, period is at least 1 seconds
	int GetCPUUseRate(void)
	{
		float systemLoad = sampler_.GetSystemLoad();
		float processLoad = sampler_.GetProcessLoad();

		int cpu_num = sampler_.GetCurrentCpus();
		int averageLoad = (0.4 * systemLoad + 0.6 * processLoad) * 100 / cpu_num;
		//printf("averageLoad is %d\n", averageLoad);
		return averageLoad;
	}
	

private:
	talk_base::CpuSampler sampler_;
};

#endif
